﻿Imports System
Imports System.Collections
Imports System.Collections.Generic
Imports System.Globalization
Imports System.Messaging
Imports System.Workflow.ComponentModel

Namespace System.Workflow.Runtime
    Public Class WorkflowQueuingService
        ' Methods
        Friend Sub New(ByVal rootWorkflowExecutor As IWorkflowCoreRuntime)
            Me.syncRoot = New Object
            Me.pendingQueueState = New EventQueueState
            Me.rootWorkflowExecutor = rootWorkflowExecutor
            Me.rootWorkflowExecutor.RootActivity.SetValue(WorkflowQueuingService.PendingMessagesProperty, Me.pendingQueueState.Messages)
            Me.persistedQueueStates = DirectCast(Me.rootWorkflowExecutor.RootActivity.GetValue(WorkflowQueuingService.RootPersistedQueueStatesProperty), Dictionary([Of] IComparable, EventQueueState))
            If (Me.persistedQueueStates Is Nothing) Then
                Me.persistedQueueStates = New Dictionary([Of] IComparable, EventQueueState)
                Me.rootWorkflowExecutor.RootActivity.SetValue(WorkflowQueuingService.RootPersistedQueueStatesProperty, Me.persistedQueueStates)
            End If
            If Not Me.Exists("*PendingNotifications") Then
                Me.CreateWorkflowQueue("*PendingNotifications", False)
            End If
        End Sub

        Friend Sub New(ByVal copyFromQueuingService As WorkflowQueuingService)
            Me.syncRoot = New Object
            Me.pendingQueueState = New EventQueueState
            Me.rootQueuingService = copyFromQueuingService
            Me.rootWorkflowExecutor = copyFromQueuingService.rootWorkflowExecutor
            Me.rootWorkflowExecutor.RootActivity.SetValue(WorkflowQueuingService.PendingMessagesProperty, Me.pendingQueueState.Messages)
            Me.persistedQueueStates = New Dictionary([Of] IComparable, EventQueueState)
            Me.rootWorkflowExecutor.RootActivity.SetValue(WorkflowQueuingService.LocalPersistedQueueStatesProperty, Me.persistedQueueStates)
            Me.SubscribeForRootMessageDelivery
        End Sub

        Private Sub AddMessageArrivedEventHandler(ByVal handler As WorkflowQueuingService)
            SyncLock Me.SyncRoot
                If (Me.messageArrivalEventHandlers Is Nothing) Then
                    Me.messageArrivalEventHandlers = New List([Of] WorkflowQueuingService)
                End If
                Me.messageArrivalEventHandlers.Add(handler)
            End SyncLock
        End Sub

        Private Sub ApplyChangesFrom(ByVal srcPendingQueueState As EventQueueState, ByVal srcPersistedQueueStates As Dictionary([Of] IComparable, EventQueueState))
            SyncLock Me.SyncRoot
                Dim dictionary As New Dictionary([Of] IComparable, EventQueueState)
                Dim pair As KeyValuePair([Of] IComparable, EventQueueState)
                For Each pair In srcPersistedQueueStates
                    If pair.Value.Transactional Then
                        If Me.persistedQueueStates.ContainsKey(pair.Key) Then
                            Dim state As EventQueueState = Me.persistedQueueStates.Item(pair.Key)
                            If Not state.Dirty Then
                                Throw New QueueException(String.Format(CultureInfo.CurrentCulture, ExecutionStringManager.QueueBusyException, New Object() { pair.Key }), MessageQueueErrorCode.QueueNotAvailable)
                            End If
                        End If
                        dictionary.Add(pair.Key, pair.Value)
                    End If
                Next
                Dim pair2 As KeyValuePair([Of] IComparable, EventQueueState)
                For Each pair2 In dictionary
                    Me.persistedQueueStates.Item(pair2.Key) = pair2.Value
                Next
                Me.pendingQueueState.CopyFrom(srcPendingQueueState)
            End SyncLock
        End Sub

        Friend Sub Complete(ByVal commitSucceeded As Boolean)
            If commitSucceeded Then
                Me.rootQueuingService.ApplyChangesFrom(Me.pendingQueueState, Me.persistedQueueStates)
            End If
            Me.UnSubscribeFromRootMessageDelivery
        End Sub

        Public Function CreateWorkflowQueue(ByVal queueName As IComparable, ByVal transactional As Boolean) As WorkflowQueue
            If (queueName Is Nothing) Then
                Throw New ArgumentNullException("queueName")
            End If
            SyncLock Me.SyncRoot
                If ((Not Me.rootQueuingService Is Nothing) AndAlso Not transactional) Then
                    Return Me.rootQueuingService.CreateWorkflowQueue(queueName, False)
                End If
                Me.NewQueue(queueName, True, transactional)
                Return New WorkflowQueue(Me, queueName)
            End SyncLock
        End Function

        Public Sub DeleteWorkflowQueue(ByVal queueName As IComparable)
            If (queueName Is Nothing) Then
                Throw New ArgumentNullException("queueName")
            End If
            SyncLock Me.SyncRoot
                If ((Not Me.rootQueuingService Is Nothing) AndAlso Not Me.IsTransactionalQueue(queueName)) Then
                    Me.rootQueuingService.DeleteWorkflowQueue(queueName)
                Else
                    Dim messages As Queue = Me.GetEventQueueState(queueName).Messages
                    Dim queue2 As Queue = Me.pendingQueueState.Messages
                    Do While (messages.Count <> 0)
                        queue2.Enqueue(messages.Dequeue)
                    Loop
                    WorkflowTrace.Runtime.TraceInformation("Queuing Service: Deleting Queue with ID {0} for {1}", New Object() { queueName.GetHashCode, queueName })
                    Me.persistedQueueStates.Remove(queueName)
                End If
            End SyncLock
        End Sub

        Friend Function DequeueEvent(ByVal queueName As IComparable) As Object
            Dim obj2 As Object
            If (queueName Is Nothing) Then
                Throw New ArgumentNullException("queueName")
            End If
            SyncLock Me.SyncRoot
                If ((Not Me.rootQueuingService Is Nothing) AndAlso Not Me.IsTransactionalQueue(queueName)) Then
                    Return Me.rootQueuingService.DequeueEvent(queueName)
                End If
                Dim eventQueueState As EventQueueState = Me.GetEventQueueState(queueName)
                If (eventQueueState.Messages.Count <> 0) Then
                    obj2 = eventQueueState.Messages.Dequeue
                Else
                    Dim args As Object() = New Object() { MessageQueueErrorCode.MessageNotFound, queueName }
                    Throw New QueueException(String.Format(CultureInfo.CurrentCulture, ExecutionStringManager.EventQueueException, args), MessageQueueErrorCode.MessageNotFound)
                End If
            End SyncLock
            Return obj2
        End Function

        Friend Sub EnqueueEvent(ByVal queueName As IComparable, ByVal item As Object)
            If (queueName Is Nothing) Then
                Throw New ArgumentNullException("queueName")
            End If
            SyncLock Me.SyncRoot
                If ((Not Me.rootQueuingService Is Nothing) AndAlso Not Me.IsTransactionalQueue(queueName)) Then
                    Me.rootQueuingService.EnqueueEvent(queueName, item)
                Else
                    Dim queue As EventQueueState = Me.GetQueue(queueName)
                    If Not queue.Enabled Then
                        Throw New QueueException(String.Format(CultureInfo.CurrentCulture, ExecutionStringManager.QueueNotEnabled, New Object() { queueName }), MessageQueueErrorCode.QueueNotAvailable)
                    End If
                    queue.Messages.Enqueue(item)
                    WorkflowTrace.Runtime.TraceInformation("Queuing Service: Enqueue item Queue ID {0} for {1}", New Object() { queueName.GetHashCode, queueName })
                    Dim i As Integer = 0
                    Do While ((Not Me.messageArrivalEventHandlers Is Nothing) AndAlso (i < Me.messageArrivalEventHandlers.Count))
                        Me.messageArrivalEventHandlers.Item(i).OnItemEnqueued(queueName, item)
                        i += 1
                    Loop
                    Me.NotifyExternalSubscribers(queueName, queue, item)
                End If
            End SyncLock
        End Sub

        Public Function Exists(ByVal queueName As IComparable) As Boolean
            If (queueName Is Nothing) Then
                Throw New ArgumentNullException("queueName")
            End If
            SyncLock Me.SyncRoot
                If ((Not Me.rootQueuingService Is Nothing) AndAlso Not Me.IsTransactionalQueue(queueName)) Then
                    Return Me.rootQueuingService.Exists(queueName)
                End If
                Return Me.persistedQueueStates.ContainsKey(queueName)
            End SyncLock
        End Function

        Private Function GetEventQueueState(ByVal queueName As IComparable) As EventQueueState
            Dim queue As EventQueueState = Me.GetQueue(queueName)
            If queue.Dirty Then
                Throw New QueueException(String.Format(CultureInfo.CurrentCulture, ExecutionStringManager.QueueBusyException, New Object() { queueName }), MessageQueueErrorCode.QueueNotAvailable)
            End If
            Return queue
        End Function

        Friend Function GetQueue(ByVal queueID As IComparable) As EventQueueState
            Dim state As EventQueueState
            If Me.persistedQueueStates.TryGetValue(queueID, state) Then
                state.queueName = queueID
                Return state
            End If
            Dim args As Object() = New Object() { MessageQueueErrorCode.QueueNotFound, queueID }
            Throw New QueueException(String.Format(CultureInfo.CurrentCulture, ExecutionStringManager.EventQueueException, args), MessageQueueErrorCode.QueueNotFound)
        End Function

        Friend Function GetQueueState(ByVal eventType As IComparable) As EventQueueState
            SyncLock Me.SyncRoot
                Return Me.GetQueue(eventType)
            End SyncLock
        End Function

        Public Function GetWorkflowQueue(ByVal queueName As IComparable) As WorkflowQueue
            If (queueName Is Nothing) Then
                Throw New ArgumentNullException("queueName")
            End If
            SyncLock Me.SyncRoot
                If ((Not Me.rootQueuingService Is Nothing) AndAlso Not Me.IsTransactionalQueue(queueName)) Then
                    Return Me.rootQueuingService.GetWorkflowQueue(queueName)
                End If
                Me.GetEventQueueState(queueName)
                Return New WorkflowQueue(Me, queueName)
            End SyncLock
        End Function

        Private Function IsNestedListenersExist(ByVal queueName As IComparable) As Boolean
            Dim i As Integer = 0
            Do While ((Not Me.messageArrivalEventHandlers Is Nothing) AndAlso (i < Me.messageArrivalEventHandlers.Count))
                Dim service As WorkflowQueuingService = Me.messageArrivalEventHandlers.Item(i)
                Dim state As EventQueueState = Nothing
                If (service.persistedQueueStates.TryGetValue(queueName, state) AndAlso (state.AsynchronousListeners.Count <> 0)) Then
                    Return True
                End If
                i += 1
            Loop
            Return False
        End Function

        Private Function IsTransactionalQueue(ByVal queueName As IComparable) As Boolean
            If Me.persistedQueueStates.ContainsKey(queueName) Then
                Return True
            End If
            Dim copyFromState As EventQueueState = Me.rootQueuingService.MarkQueueDirtyIfTransactional(queueName)
            If (Not copyFromState Is Nothing) Then
                Dim state2 As New EventQueueState
                state2.CopyFrom(copyFromState)
                Me.persistedQueueStates.Add(queueName, state2)
                Return True
            End If
            Return False
        End Function

        Private Function MarkQueueDirtyIfTransactional(ByVal queueName As IComparable) As EventQueueState
            SyncLock Me.SyncRoot
                If Not Me.persistedQueueStates.ContainsKey(queueName) Then
                    Return Nothing
                End If
                Dim queue As EventQueueState = Me.GetQueue(queueName)
                If Not queue.Transactional Then
                    Return Nothing
                End If
                If Not queue.Dirty Then
                    queue.Dirty = True
                    If (Me.dirtyQueues Is Nothing) Then
                        Me.dirtyQueues = New List([Of] IComparable)
                    End If
                    Me.dirtyQueues.Add(queueName)
                End If
                Return queue
            End SyncLock
        End Function

        Friend Sub MoveAllMessagesToPendingQueue()
            SyncLock Me.SyncRoot
                Dim messages As Queue = Me.pendingQueueState.Messages
                Dim state As EventQueueState
                For Each state In Me.persistedQueueStates.Values
                    Dim queue2 As Queue = state.Messages
                    Do While (queue2.Count <> 0)
                        messages.Enqueue(queue2.Dequeue)
                    Loop
                Next
            End SyncLock
        End Sub

        Private Sub NewQueue(ByVal queueID As IComparable, ByVal enabled As Boolean, ByVal transactional As Boolean)
            WorkflowTrace.Runtime.TraceInformation("Queuing Service: Creating new Queue with ID {0} for {1}", New Object() { queueID.GetHashCode, queueID })
            If Me.persistedQueueStates.ContainsKey(queueID) Then
                Dim args As Object() = New Object() { MessageQueueErrorCode.QueueExists, queueID }
                Throw New QueueException(String.Format(CultureInfo.CurrentCulture, ExecutionStringManager.EventQueueException, args), MessageQueueErrorCode.QueueExists)
            End If
            Dim state As New EventQueueState { _
                .Enabled = enabled, _
                .queueName = queueID, _
                .Transactional = transactional _
            }
            Me.persistedQueueStates.Add(queueID, state)
        End Sub

        Friend Sub NotifyAsynchronousSubscribers(ByVal queueName As IComparable, ByVal qState As EventQueueState, ByVal numberOfNotification As Integer)
            Dim i As Integer
            For i = 0 To numberOfNotification - 1
                Dim e As New QueueEventArgs(queueName)
                SyncLock Me.SyncRoot
                    Dim info As ActivityExecutorDelegateInfo([Of] QueueEventArgs)
                    For Each info In qState.AsynchronousListeners
                        Dim contextActivityForId As Activity = Me.rootWorkflowExecutor.GetContextActivityForId(info.ContextId)
                        info.InvokeDelegate(contextActivityForId, e, False)
                        WorkflowTrace.Runtime.TraceInformation("Queuing Service: Notifying async subscriber on queue:'{0}' activity:{1}", New Object() { queueName.ToString, info.ActivityQualifiedName })
                    Next
                End SyncLock
            Next i
        End Sub

        Private Sub NotifyExternalSubscribers(ByVal queueName As IComparable, ByVal qState As EventQueueState, ByVal eventInstance As Object)
            Me.NotifySynchronousSubscribers(queueName, qState, eventInstance)
            Me.NotifyAsynchronousSubscribers(queueName, qState, 1)
        End Sub

        Private Sub NotifySynchronousSubscribers(ByVal queueName As IComparable, ByVal qState As EventQueueState, ByVal eventInstance As Object)
            Dim e As New QueueEventArgs(queueName)
            Dim i As Integer
            For i = 0 To qState.SynchronousListeners.Count - 1
                If (Not qState.SynchronousListeners.Item(i).HandlerDelegate Is Nothing) Then
                    qState.SynchronousListeners.Item(i).HandlerDelegate.Invoke(New WorkflowQueue(Me, queueName), e)
                Else
                    qState.SynchronousListeners.Item(i).EventListener.OnEvent(New WorkflowQueue(Me, queueName), e)
                End If
            Next i
        End Sub

        Private Sub OnItemEnqueued(ByVal queueName As IComparable, ByVal item As Object)
            If Me.persistedQueueStates.ContainsKey(queueName) Then
                Dim queue As EventQueueState = Me.GetQueue(queueName)
                If Not queue.Enabled Then
                    Dim args As Object() = New Object() { MessageQueueErrorCode.QueueNotFound, queueName }
                    Throw New QueueException(String.Format(CultureInfo.CurrentCulture, ExecutionStringManager.EventQueueException, args), MessageQueueErrorCode.QueueNotAvailable)
                End If
                queue.Messages.Enqueue(item)
                Me.NotifyExternalSubscribers(queueName, queue, item)
            End If
        End Sub

        Private Sub OnItemSafeEnqueued(ByVal queueName As IComparable, ByVal item As Object)
            If Me.persistedQueueStates.ContainsKey(queueName) Then
                Dim queue As EventQueueState = Me.GetQueue(queueName)
                If Not queue.Enabled Then
                    Dim args As Object() = New Object() { MessageQueueErrorCode.QueueNotFound, queueName }
                    Throw New QueueException(String.Format(CultureInfo.CurrentCulture, ExecutionStringManager.EventQueueException, args), MessageQueueErrorCode.QueueNotAvailable)
                End If
                queue.Messages.Enqueue(item)
                Me.NotifySynchronousSubscribers(queueName, queue, item)
            End If
        End Sub

        Friend Function Peek(ByVal queueName As IComparable) As Object
            Dim obj2 As Object
            If (queueName Is Nothing) Then
                Throw New ArgumentNullException("queueName")
            End If
            SyncLock Me.SyncRoot
                If ((Not Me.rootQueuingService Is Nothing) AndAlso Not Me.IsTransactionalQueue(queueName)) Then
                    Return Me.rootQueuingService.Peek(queueName)
                End If
                Dim eventQueueState As EventQueueState = Me.GetEventQueueState(queueName)
                If (eventQueueState.Messages.Count <> 0) Then
                    obj2 = eventQueueState.Messages.Peek
                Else
                    Dim args As Object() = New Object() { MessageQueueErrorCode.MessageNotFound, queueName }
                    Throw New QueueException(String.Format(CultureInfo.CurrentCulture, ExecutionStringManager.EventQueueException, args), MessageQueueErrorCode.MessageNotFound)
                End If
            End SyncLock
            Return obj2
        End Function

        Friend Sub PostPersist(ByVal isPersistSuccessful As Boolean)
            If Not isPersistSuccessful Then
                Dim properties As TransactionalProperties = [TryCast](Me.rootWorkflowExecutor.CurrentAtomicActivity.GetValue(WorkflowExecutor.TransactionalPropertiesProperty),TransactionalProperties)
                Me.pendingQueueState = Me.pendingQueueStateSnapshot
                Me.persistedQueueStates = Me.persistedQueueStatesSnapshot
                Me.rootWorkflowExecutor.RootActivity.SetValue(WorkflowQueuingService.RootPersistedQueueStatesProperty, Me.persistedQueueStatesSnapshot)
                Me.rootWorkflowExecutor.RootActivity.SetValue(WorkflowQueuingService.PendingMessagesProperty, Me.pendingQueueStateSnapshot.Messages)
                properties.LocalQueuingService.SubscribeForRootMessageDelivery
            End If
            Me.persistedQueueStatesSnapshot = Nothing
            Me.pendingQueueStateSnapshot = Nothing
        End Sub

        Friend Sub PrePersist()
            If (Not Me.rootWorkflowExecutor.CurrentAtomicActivity Is Nothing) Then
                Dim properties As TransactionalProperties = [TryCast](Me.rootWorkflowExecutor.CurrentAtomicActivity.GetValue(WorkflowExecutor.TransactionalPropertiesProperty),TransactionalProperties)
                Me.persistedQueueStatesSnapshot = New Dictionary([Of] IComparable, EventQueueState)
                Dim pair As KeyValuePair([Of] IComparable, EventQueueState)
                For Each pair In Me.persistedQueueStates
                    Dim state As New EventQueueState
                    state.CopyFrom(pair.Value)
                    Me.persistedQueueStatesSnapshot.Add(pair.Key, state)
                Next
                Me.pendingQueueStateSnapshot = New EventQueueState
                Me.pendingQueueStateSnapshot.CopyFrom(Me.pendingQueueState)
                properties.LocalQueuingService.Complete(True)
            End If
        End Sub

        Friend Sub ProcessesQueuedAsynchronousEvents()
            Dim messages As Queue = Me.GetQueue("*PendingNotifications").Messages
            Do While (messages.Count > 0)
                Dim pair As KeyValuePair([Of] IComparable, EventQueueState) = DirectCast(messages.Dequeue, KeyValuePair([Of] IComparable, EventQueueState))
                WorkflowTrace.Runtime.TraceInformation("Queuing Service: Processing delayed message notification '{0}'", New Object() { pair.Key.ToString })
                Dim i As Integer = 0
                Do While ((Not Me.messageArrivalEventHandlers Is Nothing) AndAlso (i < Me.messageArrivalEventHandlers.Count))
                    Dim service As WorkflowQueuingService = Me.messageArrivalEventHandlers.Item(i)
                    If service.persistedQueueStates.ContainsKey(pair.Key) Then
                        Dim queue As EventQueueState = service.GetQueue(pair.Key)
                        If queue.Enabled Then
                            service.NotifyAsynchronousSubscribers(pair.Key, queue, 1)
                        End If
                    End If
                    i += 1
                Loop
                Me.NotifyAsynchronousSubscribers(pair.Key, pair.Value, 1)
            Loop
        End Sub

        Private Function QueueAsynchronousEvent(ByVal queueName As IComparable, ByVal qState As EventQueueState) As Boolean
            If ((qState.AsynchronousListeners.Count = 0) AndAlso Not Me.IsNestedListenersExist(queueName)) Then
                Return False
            End If
            Dim messages As Queue = Me.GetQueue("*PendingNotifications").Messages
            messages.Enqueue(New KeyValuePair([Of] IComparable, EventQueueState)(queueName, qState))
            WorkflowTrace.Runtime.TraceInformation("Queuing Service: Queued delayed message notification for '{0}'", New Object() { queueName.ToString })
            Return (messages.Count = 1)
        End Function

        Private Sub RemoveMessageArrivedEventHandler(ByVal handler As WorkflowQueuingService)
            SyncLock Me.SyncRoot
                If (Not Me.messageArrivalEventHandlers Is Nothing) Then
                    Me.messageArrivalEventHandlers.Remove(handler)
                End If
                If (Not Me.dirtyQueues Is Nothing) Then
                    Dim comparable As IComparable
                    For Each comparable In Me.dirtyQueues
                        Me.GetQueue(comparable).Dirty = False
                    Next
                End If
            End SyncLock
        End Sub

        Friend Function SafeEnqueueEvent(ByVal queueName As IComparable, ByVal item As Object) As Boolean
            If (queueName Is Nothing) Then
                Throw New ArgumentNullException("queueName")
            End If
            SyncLock Me.SyncRoot
                If ((Not Me.rootQueuingService Is Nothing) AndAlso Not Me.IsTransactionalQueue(queueName)) Then
                    Return Me.rootQueuingService.SafeEnqueueEvent(queueName, item)
                End If
                Dim queue As EventQueueState = Me.GetQueue(queueName)
                If Not queue.Enabled Then
                    Throw New QueueException(String.Format(CultureInfo.CurrentCulture, ExecutionStringManager.QueueNotEnabled, New Object() { queueName }), MessageQueueErrorCode.QueueNotAvailable)
                End If
                queue.Messages.Enqueue(item)
                WorkflowTrace.Runtime.TraceInformation("Queuing Service: Enqueue item Queue ID {0} for {1}", New Object() { queueName.GetHashCode, queueName })
                Dim i As Integer = 0
                Do While ((Not Me.messageArrivalEventHandlers Is Nothing) AndAlso (i < Me.messageArrivalEventHandlers.Count))
                    Me.messageArrivalEventHandlers.Item(i).OnItemSafeEnqueued(queueName, item)
                    i += 1
                Loop
                Me.NotifySynchronousSubscribers(queueName, queue, item)
                Return Me.QueueAsynchronousEvent(queueName, queue)
            End SyncLock
        End Function

        Private Sub SubscribeForRootMessageDelivery()
            If (Not Me.rootQueuingService Is Nothing) Then
                Me.rootQueuingService.AddMessageArrivedEventHandler(Me)
            End If
        End Sub

        Private Sub UnSubscribeFromRootMessageDelivery()
            If (Not Me.rootQueuingService Is Nothing) Then
                Me.rootQueuingService.RemoveMessageArrivedEventHandler(Me)
            End If
        End Sub


        ' Properties
        Friend Property CallingActivity As Activity
            Get
                If (Not Me.rootQueuingService Is Nothing) Then
                    Return Me.rootQueuingService.CallingActivity
                End If
                Return Me.caller
            End Get
            Set(ByVal value As Activity)
                If (Not Me.rootQueuingService Is Nothing) Then
                    Me.rootQueuingService.CallingActivity = value
                End If
                Me.caller = value
            End Set
        End Property

        Friend ReadOnly Property QueueNames As IEnumerable([Of] IComparable)
            Get
                Dim list As New List([Of] IComparable)(Me.persistedQueueStates.Keys)
                Dim comparable As IComparable
                For Each comparable In list
                    If (TypeOf comparable Is String AndAlso (CStr(comparable) = "*PendingNotifications")) Then
                        list.Remove(comparable)
                        Return list
                    End If
                Next
                Return list
            End Get
        End Property

        Friend ReadOnly Property SyncRoot As Object
            Get
                Return Me.syncRoot
            End Get
        End Property


        ' Fields
        Private caller As Activity
        Private dirtyQueues As List([Of] IComparable)
        Friend Shared LocalPersistedQueueStatesProperty As DependencyProperty = DependencyProperty.RegisterAttached("LocalPersistedQueueStates", GetType(Dictionary([Of] IComparable, EventQueueState)), GetType(WorkflowQueuingService))
        Private messageArrivalEventHandlers As List([Of] WorkflowQueuingService)
        Public Shared ReadOnly PendingMessagesProperty As DependencyProperty = DependencyProperty.RegisterAttached("PendingMessages", GetType(Queue), GetType(WorkflowQueuingService), New PropertyMetadata(DependencyPropertyOptions.NonSerialized))
        Private Const pendingNotification As String = "*PendingNotifications"
        Private pendingQueueState As EventQueueState
        Private pendingQueueStateSnapshot As EventQueueState
        Private persistedQueueStates As Dictionary([Of] IComparable, EventQueueState)
        Private persistedQueueStatesSnapshot As Dictionary([Of] IComparable, EventQueueState)
        Friend Shared RootPersistedQueueStatesProperty As DependencyProperty = DependencyProperty.RegisterAttached("RootPersistedQueueStates", GetType(Dictionary([Of] IComparable, EventQueueState)), GetType(WorkflowQueuingService))
        Private rootQueuingService As WorkflowQueuingService
        Private rootWorkflowExecutor As IWorkflowCoreRuntime
        Private syncRoot As Object
    End Class
End Namespace

